﻿#pragma once

#include "MathCommon.h"
#include "Reflection/Reflection.h"
#include "Containers/String.h"

#include "Vec3.m.h"


RSTRUCT()
struct WHENGINE_API SVec3
{
	ROBJECT

	RFIELD()
	Float X;

	RFIELD()
	Float Y;
	
	RFIELD()
	Float Z;

	SVec3()
	:X(0), Y(0), Z(0)
	{}

	SVec3(Float InX, Float InY,Float InZ)
		:X(InX), Y(InY), Z(InZ)
	{}

	bool operator == (const SVec3& Other) const
	{
		return X == Other.X && Y == Other.Y && Z == Other.Z;
	}

	SVec3 operator - () const
	{
		return SVec3(-X, -Y, -Z);
	}

	SVec3 operator + (const SVec3& Other) const
	{
		return SVec3(X + Other.X, Y + Other.Y, Z + Other.Z);
	}

	SVec3 operator + (const Float& Other) const
	{
		return SVec3(X + Other, Y + Other, Z + Other);
	}

	SVec3& operator += (const SVec3& Other) 
	{
		X += Other.X;
		Y += Other.Y;
		Z += Other.Z;
		return *this;
	}

	SVec3& operator += (const Float& Other)
	{
		X += Other;
		Y += Other;
		Z += Other;
		return *this;
	}


	SVec3 operator - (const SVec3& Other) const
	{
		return SVec3(X - Other.X, Y - Other.Y, Z - Other.Z);
	}
	SVec3& operator -= (const SVec3& Other)
	{
		X -= Other.X;
		Y -= Other.Y;
		Z -= Other.Z;
		return *this;
	}

	SVec3 operator * (const SVec3& Other) const
	{
		return SVec3(X * Other.X, Y * Other.Y, Z * Other.Z);
	}
	SVec3& operator *= (const SVec3& Other)
	{
		X *= Other.X;
		Y *= Other.Y;
		Z *= Other.Z;
		return *this;
	}

	SVec3 operator / (const SVec3& Other) const
	{
		return SVec3(X / Other.X, Y / Other.Y, Z / Other.Z);
	}

	SVec3& operator /= (const SVec3& Other)
	{
		X /= Other.X;
		Y /= Other.Y;
		Z /= Other.Z;
		return *this;
	}

	//返回A/B,不会出现除0错误
	SVec3 SafeDivide(const SVec3& Other,double Error=0.000001) const;
	SVec3& SafeDivideSelf(const SVec3& Other,double Error=0.000001);
	static SVec3 SafeDivide(const SVec3& A,const SVec3& B,double Error=0.000001);


	SVec3 operator - (const Float& Other) const
	{
		return SVec3(X - Other, Y - Other, Z - Other);
	}


	SVec3& operator -= (const Float& Other)
	{
		X -= Other;
		Y -= Other;
		Z -= Other;
		return *this;
	}

	SVec3 operator * (const Float & Other) const
	{
		return SVec3(X * Other, Y * Other, Z * Other);
	}

	SVec3& operator *= (const Float& Other)
	{
		X *= Other;
		Y *= Other;
		Z *= Other;
		return *this;
	}

	SVec3 operator / (Float Other) const
	{
		return SVec3(X / Other, Y / Other, Z / Other);
	}

	SVec3& operator /= (Float Other)
	{
		X /= Other;
		Y /= Other;
		Z /= Other;
		return *this;
	}

	SVec3 SafeDivide(Float Other,double Error) const;
	SVec3& SafeDivideSelf(Float Other,double Error);
	static SVec3 SafeDivide(const SVec3& A, Float B,double Error);

	Float DotProduct(const SVec3& Other) const
	{
		return X * Other.X + Y * Other.Y + Z * Other.Z;
	}

	SVec3 CrossProduct(const SVec3& Other) const
	{
		return SVec3(Y * Other.Z - Z * Other.Y, Z * Other.X - X * Other.Z, X * Other.Y - Y * Other.X);
	};

	//script constructor function
	RFUNCTION(ScriptConstructor)
	void Initialize(Float InX, Float InY, Float InZ);

	//获得向量的长度
	Float GetLength();
	//获得向量的长度的平方,比GetLength()快
	Float GetLengthSquared();

	//获取X、Y、Z中的最大值
	Float GetMax() const;

	void Normalize();

	SVec3 ToNormalized() const;

	CString ToString() const;

	void ToFloatArray(float OutArray[3]) const;
};

SVec3 operator * (const Float& Other, const SVec3& InVector);

namespace WH
{
	WHENGINE_API CString ToString(const SVec3& InValue);
}